/*
 * SIT_Progress.c : simple control that shows a bar to indicate progress
 *
 * Written by T.Pierron, Dec 05, 2008.
 */

#include "SIT_P.h"
#include <stdio.h>

	TagList ProgressClass[] = {
		{ SIT_SuperClass,  NULL,          ___, SIT_INT,  (ULONG) WidgetClass },
		{ SIT_MinValue,    "minValue",    _SG, SIT_INT,  OFFSET(SIT_Progress, pb_MinValue) },
		{ SIT_MaxValue,    "maxValue",    _SG, SIT_INT,  OFFSET(SIT_Progress, pb_MaxValue) },
		{ SIT_ProgressPos, "progressPos", _SG, SIT_INT,  OFFSET(SIT_Progress, pb_ProgressPos) },
		{ SIT_HorizScroll, "horizScroll", C__, SIT_BOOL, OFFSET(SIT_Progress, pb_IsHoriz) },
		{ SIT_TagEnd }
	};


/* Group modifications of widget into one call to avoid flicker */
static int SIT_ApplyProgressStyles(SIT_Widget w, APTR call_data, APTR user_data)
{
	SIT_Progress pb = (SIT_Progress) w;

	if (pb->pb_Mask & SIF_RANGE)
	{
		SendMessage(w->sw_Handle, PBM_SETRANGE32, pb->pb_MinValue, pb->pb_MaxValue);
		pb->pb_Mask &= ~ SIF_RANGE;
	}

	if (pb->pb_Mask & SIF_POS)
	{
		SendMessage(w->sw_Handle, PBM_SETPOS, pb->pb_ProgressPos, 0);
		pb->pb_Mask &= ~ SIF_POS;
	}
	w->sw_PostProcess = NULL;
	return 0;
}

static int SIT_SetProgressValues(SIT_Widget w, APTR call_data, APTR user_data)
{
	TagList *     tag   = call_data;
	SIT_Variant * value = user_data;
	SIT_Progress  pb    = (SIT_Progress) w;
	int           isSet = 0;

	switch (tag->tl_TagID) {
	case SIT_MinValue:    pb->pb_MinValue    = value->integer; isSet = SIF_RANGE; break;
	case SIT_MaxValue:    pb->pb_MaxValue    = value->integer; isSet = SIF_RANGE; break;
	case SIT_ProgressPos: pb->pb_ProgressPos = value->integer; isSet = SIF_POS;   break;
	case SIT_HorizScroll: pb->pb_IsHoriz     = value->integer; break;
	default: return SIT_SetWidgetValue(w, call_data, user_data); // super class
	}

	if (isSet)
	{
		pb->pb_Mask |= isSet;
		w->sw_PostProcess = SIT_ApplyProgressStyles;
	}
	return 0;
}

/* Set minimal width/height */
static int SIT_MeasureProgress(SIT_Widget w, APTR call_data, APTR user_data)
{
	SIT_Progress pb  = (SIT_Progress) w;
	SIZE *       ret = call_data;

	if (pb->pb_IsHoriz)
		ret->cy = GetSystemMetrics(SM_CYHSCROLL);
	else
		ret->cx = GetSystemMetrics(SM_CXVSCROLL);
	return 0;
}

static int SIT_RefreshTextCache(SIT_Progress pb)
{
	if (pb->pb_ProgressPos == pb->pb_PosCache && pb->pb_TextCache)
		return wcslen(pb->pb_TextCache);

	int    len = MultiByteToWideChar(CP_UTF8, 0, pb->super.sw_Title, -1, NULL, 0);
	LPWSTR fmt = alloca(len * sizeof *fmt);

	MultiByteToWideChar(CP_UTF8, 0, pb->super.sw_Title, -1, fmt, len);
	len = (len + 25) & ~15;
	pb->pb_TextCache = realloc(pb->pb_TextCache, len);
	return wsprintf(pb->pb_TextCache, fmt, pb->pb_PosCache = pb->pb_ProgressPos);
}

static LRESULT CALLBACK SIT_ProgressSubClassHandler(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	SIT_Progress pb = (APTR) GetProp(wnd, sit_class);
	LRESULT res;

	if (message == WM_PAINT && IsDef(pb->super.sw_Title))
	{
		SIZE  sz;
		RECT  rect, upd, region;
		HDC   hdc = GetDC(pb->super.sw_Handle);
		HFONT fnt = SelectObject(hdc, pb->super.sw_Font);
		int   len = SIT_RefreshTextCache(pb);

		GetTextExtentPoint32(hdc, pb->pb_TextCache, len, &sz);
		GetUpdateRect(wnd, &upd, FALSE);
		GetClientRect(pb->super.sw_Handle, &rect);
		rect.left   = (rect.right  - sz.cx) >> 1;
		rect.top    = (rect.bottom - sz.cy) >> 1;
		rect.right  = rect.left + sz.cx;
		rect.bottom = rect.top  + sz.cy;
		if (! IntersectRect(&region, &upd, &rect))
			return CallWindowProc(pb->super.sw_SuperProc, wnd, message, wParam, lParam);

		InvalidateRect(wnd, &rect, TRUE);
		res = CallWindowProc(pb->super.sw_SuperProc, wnd, message, wParam, lParam);
		SetTextColor(hdc, 0);
		SetBkMode(hdc, TRANSPARENT);
		SetTextAlign(hdc, TA_TOP);
		TextOut(hdc, rect.left, rect.top, pb->pb_TextCache, len);
		SelectObject(hdc, fnt);
		DeleteDC(hdc);
		return res;
	}
	else return CallWindowProc(pb->super.sw_SuperProc, wnd, message, wParam, lParam);
}

static int SIT_FinalizeProgress(SIT_Widget w, APTR call_data, APTR user_data)
{
	#define	pb   ((SIT_Progress)w)
	if (pb->pb_TextCache) free(pb->pb_TextCache);
	return 1;
	#undef pb
}

/* Control creation */
BOOL SIT_CreateProgress(SIT_Widget w, va_list args)
{
	SIT_Progress pb = (SIT_Progress) w;
	HWND         hwnd;
	int          style = WS_CHILD | PBS_SMOOTH;

	/* Subclass SetValues */
	w->sw_SetValue = SIT_SetProgressValues;
	w->sw_OptimalWidth = SIT_MeasureProgress;
	w->sw_Finalize = SIT_FinalizeProgress;

	/* Default values */
	pb->pb_IsHoriz  = True;
	pb->pb_MaxValue = 100;
	SIT_ParseTags(w, args, w->sw_Class = ProgressClass);

	if (IsVisible(w))    style |= WS_VISIBLE;
	if (!pb->pb_IsHoriz) style |= PBS_VERTICAL;

	/* Create Win32 control, pos and dim will be set later */
	hwnd = w->sw_Handle = CreateWindowEx(0, PROGRESS_CLASS, w->sw_Name, style,
		0, 0, 10, 10, SIT_GetContainer(w), (HMENU) MAKE_ID(w), instance, NULL);

	if (hwnd == NULL) return FALSE;
	SIT_SetDefaultFont(w);

	SetProp(hwnd, sit_class, (HANDLE) w);

	w->sw_SuperProc = (APTR) GetWindowLong(w->sw_Handle, GWL_WNDPROC);
	SetWindowLong(w->sw_Handle, GWL_WNDPROC, (LONG) SIT_ProgressSubClassHandler);

	// If user hasn't set range at creation time, we do it now
	pb->pb_Mask |= SIF_RANGE;

	if (w->sw_PostProcess)
		w->sw_PostProcess(w, NULL, NULL);

	return TRUE;
}
